R Markdown

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.

When you click the Knit button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:

Introduction

On 31 December 2018, Iain Agar published his work on the 10 year history of homicides in London on Kaggle . The data set was named “mmap.xlsx” This is the link to the Kaggle site: https://www.kaggle.com/iainagar/london-homicide-data-20082018

The London homicide dataset

Ager stated that there was no readily available London homicide dataset in the public domain. His mmap dataset was constructed using a number of open resources, most notably the murdermap website.

I imported his data set mmap.xlsx into R which covered the period from Jan 2008 to Dec 2018, and renamed the data frame it as mmap2018

I contacted the publisher of the murdermap.co.uk website in London who generously agreed to provide additional homicide cases for the period 1 Jan 2019 to 1 November 2020.

I bound the additional 2019 and 2020 cases to the orginal mmap.xlsx data set produced by Iain Agar and named the merged frame set as mmap.

I imported details of the borough population from Iain Agers data set boroughpop and integrated this into the mmap data frame.

I completed a range of data wrangling to ensure that the factor descriptions were consistent across years as between the original 2018 data set and the augmented 2019 and 2020 data sets. For example I before bringing the three data sets back into R. I had to manually define ethnicity for the data in 2019 and 2020 based a review of the murder map people profiles on the murder map website and aligned consistent names for cause of death which changed in the most recent murder map profiles. I extended the ID variable created by Agar in 2018 and applied the same ID methodology to the incremental cases in 2019 and 2020. Finally I needed to create consistency across the period 2000 to 2020 in the status variable which the publisher had made numerous changes to in 2019 and 2020.

The bedrock of the analysis and visualisation work in this RMD is the mmap data frame - which covers the period January 2008 to November 1 2020.

For time series analysis comparing variables by year I filtered to just include the full year data from 2008 to 2019. For sociographic and demographic data that is not comparing variables by year I used all cases through 1 November, 2020.

Victim demographics summary [Do a final update on the overall so whats]


# Install packages
detach("package:sp", unload = TRUE)
install.packages("sp", dependencies=TRUE)
install.packages("dplyr")
install.packages("tidyr")
install.packages("lubridate")
install.packages("ggplot2")
install.packages("sp")
install.packages("vcd")
install.packages("GGally")
install.packages("colourpicker")
install.packages("rgeos")
install.packages("Hmisc",repos = "http://cran.us.r-project.org")
install.packages("gapminder")
install.packages("googleVis")
install.packages("plotly")
install.packages('acepack')
install.packages("cowplot")
install.packages("maptools") 
install.packages("ggmap") 
install.packages("broom")
install.packages("mapproj")
install.packages("leaflet")
install.packages("ggmosaic")
install.packages("leaflet.extras")
install.packages("tidyverse")
install.packages("reshape")
install.packages("ggridges")
install.packages("rgdal")

Import data sets, integrate into a mmap data frame covering cases from 2008 to 2020

Consolidate the mmap data bases from 2018, 2019 and 2020 to update the original Iain Agar 2018 data set to November 2020.

String variables were reformatted as factors.

## Loading libraries and reading data

# The libraries used in this rmd are provided in the code below.

library(knitr)
library(readxl)
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.0.3
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.0.3
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(tidyr)
## Warning: package 'tidyr' was built under R version 4.0.3
library(tibble)
library(stringr)
library(lubridate)
## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
library(leaflet)
## Warning: package 'leaflet' was built under R version 4.0.3
library(leaflet.extras)
## Warning: package 'leaflet.extras' was built under R version 4.0.3
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.0.3
## -- Attaching packages --------------------------------------- tidyverse 1.3.0 --
## v readr   1.3.1     v forcats 0.5.0
## v purrr   0.3.4
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x lubridate::as.difftime() masks base::as.difftime()
## x lubridate::date()        masks base::date()
## x dplyr::filter()          masks stats::filter()
## x lubridate::intersect()   masks base::intersect()
## x dplyr::lag()             masks stats::lag()
## x lubridate::setdiff()     masks base::setdiff()
## x lubridate::union()       masks base::union()
library(reshape)
## Warning: package 'reshape' was built under R version 4.0.3
## 
## Attaching package: 'reshape'
## The following object is masked from 'package:lubridate':
## 
##     stamp
## The following objects are masked from 'package:tidyr':
## 
##     expand, smiths
## The following object is masked from 'package:dplyr':
## 
##     rename
library(ggridges)
## Warning: package 'ggridges' was built under R version 4.0.3
## Import the data - London Homicide data, and London borough population data.

# import original Iain Ager mmap.xlsx into R and save it as mmap18
library(readxl)
mmap18 <- read_excel("C:/Users/david/OneDrive - RMIT University/Data Visualisation and Communication/London Homicides Project/mmap.xlsx")


# clean up the orginal data set and eliminate redundant variables

library(dplyr)
mmap18 = select(mmap18, -6,-7,-8,-13,-14,-16,-17,-18,-19)

# reorder columns
mmap18 <- mmap18[ , c(2, 1, 8, 9,5,4,3,10,6,11,7)]  


# update column names
colnames(mmap18) <- c("date", "ID", "latitude", "longitude", "ethnicity", "sex", "age", "ageGroup", "weapon", "borough", "status")

# change strings to factors
mmap18 <- mmap18 %>% mutate_if(is.character, as.factor) 

# import the 2019 murder map data into R
mmap19 <- read_excel("C:/Users/david/OneDrive - RMIT University/Data Visualisation and Communication/London Homicides Project/Murdermap2019.xlsx")

mmap19 = select(mmap19, -3,-6)


mmap19$longitude <- as.numeric(mmap19$longitude)


# change strings to factors
mmap19 <- mmap19 %>% mutate_if(is.character, as.factor) 

colnames(mmap19) <- c("date", "ID", "latitude", "longitude", "ethnicity", "sex", "age", "ageGroup", "weapon", "borough", "status")

# import the 2019 murder map data into R
mmap20 <- read_excel("C:/Users/david/OneDrive - RMIT University/Data Visualisation and Communication/London Homicides Project/Murdermap2020.xlsx")

mmap20 = select(mmap20, -3,-6)

mmap20 <- mmap20 %>% mutate_if(is.character, as.factor) 

colnames(mmap20) <- c("date", "ID", "latitude", "longitude", "ethnicity", "sex", "age", "ageGroup", "weapon", "borough", "status")


##Merge mmap19 and mmap 20 using rbind function
mmap19_20 = rbind(mmap19,mmap20)

#change the levels for "sex" to align with mmap18
mmap19_20 <- mmap19_20 %>%
  mutate(sex = fct_recode(sex,
                             "M" = "Male",
                             "F" = "Female")) 

# merge mmap19_20 with mmap18 to create mmap (integrated cases from 2008 to 2020)
mmap = rbind(mmap18, mmap19_20)

##Data Wrangling:

# See all levels in weapon variable
levels(mmap$weapon) 
##  [1] "Arson"         "Blunt Object"  "Gun"           "Knife"        
##  [5] "Ligature"      "None"          "Other"         "Poison"       
##  [9] "Strangulation" "Vehicle"       "Drug"          "Fire"         
## [13] "Unknown"
# Replicate weapon column to enable re-factoring
mmap2 = cbind(mmap, weapon2=rep(mmap$weapon)) 



# Change levels in Weapon column to include just 4 levels Knife, Gun, Assault and Other
mmap3 <- mmap2 %>%
  mutate(weapon = fct_recode(weapon,
                             "Other" = "Arson",
                             "Other" = "Vehicle",
                             "Other" = "Drug",
                             "Other" = "Poison",
                             "Other" = "Unknown",
                             "Other" = "Ligature",
                             "Other" = "Strangulation",
                             "Other" = "Fire",
                             "Knife" = "Knife",
                             "Gun" = "Gun",
                             "Other" = "Blunt Object",
                             "Assault" = "Assault",
                             "Assault" = "None")) 
## Warning: Problem with `mutate()` input `weapon`.
## i Unknown levels in `f`: Assault
## i Input `weapon` is `fct_recode(...)`.
## Warning: Unknown levels in `f`: Assault
# clean up the factor names within borough variable to enable the bind with boroughpop (ensure they are exactly the same!)
mmap3 <- mmap3 %>% mutate(borough = fct_recode(borough, 
                              "Westminster" = "City of Westminster",
                              "Kingston upon Thames" = "Kingston",
                              "Kingston upon Thames" = "Kingston-upon-Thames",
                              "Kingston upon Thames" = "Kingston Upon Thames",
                              "Kingston upon Thames" = "Kingston-Upon-Thames",
                              "Richmond upon Thames" = "Richmond"))
## Warning: Problem with `mutate()` input `borough`.
## i Unknown levels in `f`: Kingston, Kingston Upon Thames
## i Input `borough` is `fct_recode(...)`.
## Warning: Unknown levels in `f`: Kingston, Kingston Upon Thames
# Replicate date column
mmap4 = cbind(mmap3, date2=rep(mmap3$date))


# create new data frame mmap5 and separate date variable from mmap4 into year, month and day and save them as integers
mmap5 = separate(mmap4, date2, c("year", "month", "day"), "-") %>%
  mutate_if(is.character, as.integer) 

mmap5 <- mmap5 %>% mutate(status = fct_recode(status, 
                              "Awaiting Trial" = "Awaiting trial",
                              "Awaiting Trial" = "Awaiting Outcome",
                              "Solved" = "Solved",
                              "Solved" = "Self Defence",
                              "Unsolved" = "Suspect dead",
                              "Unsolved" = "Unsolved"))



mmap5 <- mmap5 %>% mutate(ethnicity = fct_recode(ethnicity, 
                              "Other" = "Mixed",
                              "Black" = "Black",
                              "Black" = "Black or Black British",
                              "White" = "White",
                              "White" = "White or White British",
                              "Asian" = "Asian",
                              "Asian" = "Asian or Asian British",
                              "Other" = "Unknown",
                              "Other" = "NA",
                              "Other" = "Any Other Ethnic Appearance"))
## Warning: Problem with `mutate()` input `ethnicity`.
## i Unknown levels in `f`: NA
## i Input `ethnicity` is `fct_recode(...)`.
## Warning: Unknown levels in `f`: NA
levels(mmap5$ethnicity)
## [1] "Other" "Asian" "Black" "White"
# read the boroughpop file into R to access borough population data
boroughpop <- read_excel("boroughpop.xlsx")


# change column names in boroughpop
colnames(boroughpop) = c("borough", "population")

# join mmap5 and boroughpop data frames using "borough" 
mmap6 <- left_join(mmap5, boroughpop, by = "borough")


# make bourough a factor variable
mmap6$borough <- as.factor(mmap6$borough)


# create new variable for counting homicides by borough and homicides per 100,000 population by borough
mmap6_sum <- mmap6 %>% select(borough, population) %>% group_by(borough) %>% mutate(count = n(), population = population, homicide_rate = (count*100000)/11/population) %>% distinct()
                                                                                    
# create mmap 7 by filtering mmap5 to just include full year data to end of calendar 2019
mmap7 <- mmap6 %>% filter(year != "2020")


mmap7 <-data.frame(mmap7)

# remove NA cases for ethicity
mmap8 <- mmap7 %>% filter(ethnicity != "NA")

# save mmap6_sum as data frame and name the data frame mmap9                                                                               
mmap9 <- as.data.frame(mmap6_sum)

# create new data frame mmap10 with just borough and homicide rate variables
mmap10 <- mmap9 %>% select(borough, homicide_rate)

# round the homicide_rate variable to 2 decimal places
mmap10$homicide_rate <- round(mmap10$homicide_rate, 2)

# arrange the data frame based on homicide rate variable descending order
mmap10 <- mmap10 %>% arrange(desc(mmap10$homicide_rate)) 

Data exploration

I have extended Iain’s data exploration to include calender 2019 data and YTD calendar 2020 data sourced from the murder map web site publisher in London.

Based on this additional data there were 149 new homicide cases in 2019 and 107 new homicide cases year-to-data at 1 November 2020.

I will include the 2019 data for exploration of the 11 year annual temporal trends from 2008 to 2019 and will include both the 2019 and 2020 cases for the 12 year mix of homicides by demographics such as gender, ethnicity and age. This is because I only have year to data homicide data for the 2020 cases.

key observations about the temporal trends in london homicide for the 11 years from 2008 to 2019:

Geography

choropleth map

# Install ggplot2 mapping packages

library(rgeos)
## Warning: package 'rgeos' was built under R version 4.0.3
## Loading required package: sp
## Warning: package 'sp' was built under R version 4.0.3
## rgeos version: 0.5-5, (SVN revision 640)
##  GEOS runtime version: 3.8.0-CAPI-1.13.1 
##  Linking to sp version: 1.4-4 
##  Polygon checking: TRUE
library(ggmap)
## Warning: package 'ggmap' was built under R version 4.0.3
## Google's Terms of Service: https://cloud.google.com/maps-platform/terms/.
## Please cite ggmap if you use it! See citation("ggmap") for details.
## 
## Attaching package: 'ggmap'
## The following object is masked from 'package:cowplot':
## 
##     theme_nothing
## The following object is masked from 'package:plotly':
## 
##     wind
library(maptools)
## Warning: package 'maptools' was built under R version 4.0.3
## Checking rgeos availability: TRUE
library(broom)
## Warning: package 'broom' was built under R version 4.0.3
library(mapproj)
## Warning: package 'mapproj' was built under R version 4.0.3
## Loading required package: maps
## Warning: package 'maps' was built under R version 4.0.3
## 
## Attaching package: 'maps'
## The following object is masked from 'package:purrr':
## 
##     map
library(rgdal)
## Warning: package 'rgdal' was built under R version 4.0.3
## rgdal: version: 1.5-18, (SVN revision 1082)
## Geospatial Data Abstraction Library extensions to R successfully loaded
## Loaded GDAL runtime: GDAL 3.0.4, released 2020/01/28
## Path to GDAL shared files: C:/Users/david/OneDrive/Personal and Family/R/win-library/4.0/rgdal/gdal
## GDAL binary built with GEOS: TRUE 
## Loaded PROJ runtime: Rel. 6.3.1, February 10th, 2020, [PJ_VERSION: 631]
## Path to PROJ shared files: C:/Users/david/OneDrive/Personal and Family/R/win-library/4.0/rgdal/proj
## Linking to sp version:1.4-4
## To mute warnings of possible GDAL/OSR exportToProj4() degradation,
## use options("rgdal_show_exportToProj4_warnings"="none") before loading rgdal.
# create Leaflet interactive cloropeth chart for Homicide Rate

# read shp file for just London boroughs
London_Ward2 <- readShapeSpatial("London_Borough_Excluding_MHW.shp")
## Warning: readShapeSpatial is deprecated; use rgdal::readOGR or sf::st_read
## Warning: readShapePoly is deprecated; use rgdal::readOGR or sf::st_read
# convert coordinates into lat long degrees
proj4string(London_Ward2) <- CRS("+init=epsg:27700")
## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj =
## prefer_proj): Discarded datum OSGB_1936 in CRS definition
London_Ward2.wgs84 <- spTransform(London_Ward2, CRS("+init=epsg:4326"))


library(leaflet)

# For Leaflet choropleth maps, we need to use a SpatialPolygonDataFrame

class(London_Ward2.wgs84)
## [1] "SpatialPolygonsDataFrame"
## attr(,"package")
## [1] "sp"
names(London_Ward2.wgs84)
## [1] "NAME"       "GSS_CODE"   "HECTARES"   "NONLD_AREA" "ONS_INNER" 
## [6] "SUB_2009"   "SUB_2006"
# Rename the borough variable in mmap10 to "NAME" to match the "SpatialPolygonsDataFrame" file London_Ward2.wgs84

names(mmap10)[names(mmap10) == "borough"] <- "NAME"

str(mmap10)
## 'data.frame':    33 obs. of  2 variables:
##  $ NAME         : Factor w/ 33 levels "Barking and Dagenham",..: 7 28 14 22 12 19 25 33 11 4 ...
##  $ homicide_rate: num  7.13 2.52 2.38 2.36 2.34 2.32 2.25 2.19 2.15 2.13 ...
mmap10 <- mmap10 %>% mutate(NAME = fct_recode(NAME, 
                                                        
                             "City of London" = "City and County of the City of London",
                            
                           "Westminster" = "City of Westminster"))  
## Warning: Problem with `mutate()` input `NAME`.
## i Unknown levels in `f`: City and County of the City of London, City of Westminster
## i Input `NAME` is `fct_recode(...)`.
## Warning: Unknown levels in `f`: City and County of the City of London, City of
## Westminster
levels(mmap10$NAME)
##  [1] "Barking and Dagenham"   "Barnet"                 "Bexley"                
##  [4] "Brent"                  "Bromley"                "Camden"                
##  [7] "City of London"         "Croydon"                "Ealing"                
## [10] "Enfield"                "Greenwich"              "Hackney"               
## [13] "Hammersmith and Fulham" "Haringey"               "Harrow"                
## [16] "Havering"               "Hillingdon"             "Hounslow"              
## [19] "Islington"              "Kensington and Chelsea" "Kingston upon Thames"  
## [22] "Lambeth"                "Lewisham"               "Merton"                
## [25] "Newham"                 "Redbridge"              "Richmond upon Thames"  
## [28] "Southwark"              "Sutton"                 "Tower Hamlets"         
## [31] "Waltham Forest"         "Wandsworth"             "Westminster"
# merge mmap data into London_Ward.wgs84 SpatialPolygonsDataFrame using "DISTRICT"
merge.mmap10 <- sp::merge(London_Ward2.wgs84, mmap10, by = "NAME", duplicateGeoms = TRUE)


# create a discrete colour scale based on quantiles for five levels

bins <- quantile(
  mmap10$homicide_rate,
  probs = seq(0,1,.2), names = FALSE, na.rm = TRUE)
bins
## [1] 0.560 0.916 1.548 1.890 2.226 7.130
# bins now contains five sequential colour levels so that 20 per cent of the data falls within each bin. The following histogram visualises the breaks used to create the scale.

ggplot(data = mmap10,
       aes(x = homicide_rate)) +
  geom_histogram(colour = "white", bins = 40) +
  geom_vline(
    xintercept = quantile(
      mmap10$homicide_rate,
      probs = seq(0,1,0.2), na.rm = TRUE),
    colour = "red", lwd = 1, lty = 2)

# Bins can be used to create a colour scale, named pal, using the colorBin() function, which maps the bins to a palette. Select the YlOrRd palette from the ColourBrewer package

pal <- colorBin(
  "YlOrRd",
  domain = mmap10$homicide_rate,
  bins = bins
  )

# add the colour scale to the choropleth map.
labels <- sprintf(
  "%s
%g homicide_rate",
  merge.mmap10$NAME,
  merge.mmap10$homicide_rate
) %>% lapply(htmltools::HTML)

library(htmlwidgets)
## Warning: package 'htmlwidgets' was built under R version 4.0.3
library(htmltools)

title <- tags$div(
   HTML('<h3>Average London borough homicide rate per 100,000 population 2008:2019</h3>')
 )
p3 <- leaflet(merge.mmap10) %>%
  setView(lng = -0.118092 , lat = 51.509865, zoom = 10)
p3 %>% addPolygons(
  fillColor = ~pal(homicide_rate),
  weight = 2,
  opacity = 1,
  color = "white",
  dashArray = "3",
  fillOpacity = 0.7,
  highlight = highlightOptions(
    weight = 5,
    color = "#666",
    dashArray = "",
    fillOpacity = 0.7,
    bringToFront = TRUE),
  label = labels,
  labelOptions = labelOptions(
    style = list("font-weight" = "normal", padding = "3px 8px"),
    textsize = "15px",
    direction = "auto")) %>%
  addLegend(pal = pal,
            values = ~homicide_rate,
            opacity = 0.7, title = "Homicide Rate",
  position = "bottomright") %>%
  addControl(title, position = "topright")

Geography

Leaflet Maps

This section is a sample of maps using the Leaflet package.

Layered point map by weapon

The layered point map simple shows the distribution of all homicide offenses in the data for 2008-2020 and provides coloured circles based on the type of weapon used in the homicide. This visualisation is an extension of the original visualisation created by Iain Agar in 2018 but includes new data for 2019 and 2020

pal <- colorFactor(palette = c("red", "blue", "dark green", "black"),
                    levels = c("Knife", "Gun", "Assault", "Other")) # Creating a 4 colour palette

knife <- mmap5 %>%
  filter(weapon == "Knife") # Grouping layers - knife

gun <- mmap5 %>%
  filter(weapon == "Gun") # Grouping layers - gun

assault <- mmap5 %>%
  filter(weapon == "Assault") # Grouping layers - none

other <- mmap5 %>%
  filter(weapon == "Other") # Grouping layers - other


library(leaflet)

mmap5 %>%
 leaflet() %>%
  setView(lng=-0.1, lat=51.51, zoom=10) %>%
  addProviderTiles("CartoDB") %>%
  addScaleBar(position = "bottomleft") %>%
  addCircleMarkers(data = knife,
                   lng = ~longitude, 
                   lat = ~latitude, 
                   radius = 2, 
                   color = ~pal(weapon),
                   group = "Knife",
                   popup = ~paste("<b>", ID, "</b>", "<br/>", date, "<br/>", age, "<br/>", sex, "<br/>", weapon, "<br/>", status)) %>%
  addCircleMarkers(data = gun,
                   lng = ~longitude, 
                   lat = ~latitude, 
                   radius = 2, 
                   color = ~pal(weapon),
                   group = "Gun",
                   popup = ~paste("<b>", ID, "</b>", "<br/>", date, "<br/>", age, "<br/>", sex, "<br/>", weapon, "<br/>", status)) %>%
  addCircleMarkers(data = assault,
                   lng = ~longitude, 
                   lat = ~latitude, 
                   radius = 2, 
                   color = ~pal(weapon),
                   group = "Assault",
                   popup = ~paste("<b>", ID, "</b>", "<br/>", date, "<br/>", age, "<br/>", sex, "<br/>", weapon, "<br/>", status)) %>%
  addCircleMarkers(data = other,
                   lng = ~longitude, 
                   lat = ~latitude, 
                   radius = 2, 
                   color = ~pal(weapon),
                   group = "Other",
                   popup = ~paste("<b>", ID, "</b>", "<br/>", date, "<br/>", age, "<br/>", sex, "<br/>", weapon, "<br/>", status)) %>%

  addLegend(position = "bottomright", 
            pal = pal, 
            values = c("Knife", "Gun", "Assault", "Other"),
            title = "Legend") %>%
  addLayersControl(
    overlayGroups = c("Knife",
                      "Gun",
                      "Assault",
                      "Other"))

Layered point map by ethnicity

*This layered point map shows the distribution of all homicide offences in the data for 2008-2020 and provides coloured circles based on the ethnicity of the victim.

pal <- colorFactor(palette = c("red", "blue", "dark green", "black", "purple"),
                    levels = c("Black", "White", "Asian", "Mixed", "Unknown")) # Creating a 5 colour palette

black <- mmap5 %>%
  filter(ethnicity == "Black") # Grouping layers - black

white <- mmap5 %>%
  filter(ethnicity == "White") # Grouping layers - white

asian <- mmap5 %>%
  filter(ethnicity == "Asian") # Grouping layers - asian

mixed <- mmap5 %>%
  filter(ethnicity == "Mixed") # Grouping layers - mixed

unknown <- mmap5 %>%
  filter(ethnicity == "Unknown") # Grouping layers - unknown


library(leaflet)

mmap5 %>%
 leaflet() %>%
  setView(lng=-0.1, lat=51.51, zoom=10) %>%
  addProviderTiles("CartoDB") %>%
  addScaleBar(position = "bottomleft") %>%
  addCircleMarkers(data = black,
                   lng = ~longitude, 
                   lat = ~latitude, 
                   radius = 2, 
                   color = ~pal(ethnicity),
                   group = "Black",
                   popup = ~paste("<b>", ID, "</b>", "<br/>", date, "<br/>", age, "<br/>", sex, "<br/>", weapon, "<br/>", status)) %>%
  addCircleMarkers(data = white,
                   lng = ~longitude, 
                   lat = ~latitude, 
                   radius = 2, 
                   color = ~pal(ethnicity),
                   group = "White",
                   popup = ~paste("<b>", ID, "</b>", "<br/>", date, "<br/>", age, "<br/>", sex, "<br/>", weapon, "<br/>", status)) %>%
  addCircleMarkers(data = asian,
                   lng = ~longitude, 
                   lat = ~latitude, 
                   radius = 2, 
                   color = ~pal(ethnicity),
                   group = "Asian",
                   popup = ~paste("<b>", ID, "</b>", "<br/>", date, "<br/>", age, "<br/>", sex, "<br/>", weapon, "<br/>", status)) %>%
  addCircleMarkers(data = mixed,
                   lng = ~longitude, 
                   lat = ~latitude, 
                   radius = 2, 
                   color = ~pal(ethnicity),
                   group = "Mixed",
                   popup = ~paste("<b>", ID, "</b>", "<br/>", date, "<br/>", age, "<br/>", sex, "<br/>", weapon, "<br/>", status)) %>%
    addCircleMarkers(data = unknown,
                   lng = ~longitude, 
                   lat = ~latitude, 
                   radius = 2, 
                   color = ~pal(ethnicity),
                   group = "Unknown",
                   popup = ~paste("<b>", ID, "</b>", "<br/>", date, "<br/>", age, "<br/>", sex, "<br/>", weapon, "<br/>", status)) %>%

  addLegend(position = "bottomright", 
            pal = pal, 
            values = c("Black", "White", "Asian", "Mixed", "Unknown"),
            title = "Legend") %>%
  addLayersControl(
    overlayGroups = c("Black",
                      "White",
                      "Asian",
                      "Mixed", "Unknown"))

Cluster map, female victims

The cluster map is filtered to show the location of all female homicides in the period 2008 to 2020. Key concentrations at the county level include:

  • Lower Holloway
  • Hoxton/Shorditch
  • Stepney
  • Southwark
femaleVictims <- mmap5 %>%
  filter(sex == 'F')

femaleVictims %>% # Map showing all point data
 leaflet() %>%
  setView(lng =-0.1, lat=51.51, zoom=10) %>%
  addProviderTiles(providers$OpenStreetMap) %>%
  addScaleBar %>%
  addCircleMarkers(lng = ~longitude, lat = ~latitude, popup = ~paste0("<b>", ID, "</b>", "<br/>", date, "<br/>", age, "<br/>", sex, "<br/>", weapon, "<br/>", borough), radius = 4, clusterOptions = markerClusterOptions)